#include "head.h"

int trans_exit = 0;//退出标记位,1表示有退出信号
void func(int num){
    trans_exit = 1;
}
//用户下载，接收服务端发来的文件
int recv_file(const char *file_name, int socket_fd){
    int fd = open(file_name, O_RDWR | O_CREAT, 0666);
    //获取偏移量
    struct stat stat_file;
    fstat(fd, &stat_file);
    off_t offset = stat_file.st_size;
    //向服务端发送偏移量
    send(socket_fd, &offset, sizeof(off_t), MSG_NOSIGNAL);

    //接收文件大小
    off_t file_size;
    recv(socket_fd, &file_size, sizeof(off_t), MSG_WAITALL);
    //接收文件哈希值
    char net_file_hash[FILE_HASH_SIZE + 1] = {0};
    recv(socket_fd, net_file_hash, FILE_HASH_SIZE, MSG_WAITALL);

    ftruncate(fd, file_size);

    char *p = (char *)mmap(NULL, file_size, PROT_READ | PROT_WRITE,
                           MAP_SHARED, fd, 0);
    if(p == MAP_FAILED){
        printf("Download failed.\n");
        return -1;
    }
    char *curr = p + offset;

    printf("Downloading...\n");
    printf("Download: %.2f%%\n", (float)offset/file_size *100);

    //接收文件
    signal(2, func);
    int recv_count = recv(socket_fd, curr, file_size - offset, MSG_WAITALL);
    offset += recv_count;
    if(trans_exit == 1){
        //有退出信号
        printf("Download: %.2f%%\n", (float)offset/file_size *100);
        printf("Download stopped.\n");
        munmap(p, file_size);
        ftruncate(fd, offset);
        close(fd);
        close(socket_fd);
        signal(2, SIG_DFL);
        exit(1);
    }

    printf("Download: %.2f%%\n", (float)offset/file_size *100);
    if(offset == file_size){
        //检查哈希值
        char local_file_hash[FILE_HASH_SIZE + 1];
        hash_count(file_name, local_file_hash, sizeof(local_file_hash));
        if(!strcmp(net_file_hash, local_file_hash)){
            printf("Download success\n");
        }
        else{
            printf("File corrupted.\nPlease delete the file and re-download it.\n");
        }
    }
    else{
        printf("Download failed.\nNetwork connection interrupted.\n");
    }

    munmap(p, file_size);
    ftruncate(fd, offset);
    close(fd);
    signal(2, SIG_DFL);
    return 0;
}

//用户上传，向服务器发送文件
int send_file(const char *file_name, int socket_fd){
    //发送文件哈希值
    char file_hash[FILE_HASH_SIZE + 1];
    hash_count(file_name, file_hash, sizeof(file_hash));
    send(socket_fd, file_hash, FILE_HASH_SIZE, MSG_NOSIGNAL);

    //判断秒传
    int flag;
    recv(socket_fd, &flag, sizeof(int), MSG_WAITALL);
    if(flag == 1){
        printf("Instant upload success.\n");
        return 0;
    }

    int fd = open(file_name, O_RDWR);
    if(fd == -1){
        printf("file does not exists\n");
        return -1;
    }

    //获取文件大小
    struct stat stat_file;
    fstat(fd, &stat_file);
    off_t file_size = stat_file.st_size;

    //发送文件大小
    send(socket_fd, &file_size, sizeof(off_t), MSG_NOSIGNAL);


    //接收起始偏移量
    off_t offset;
    recv(socket_fd, &offset, sizeof(off_t), MSG_WAITALL);

    printf("Upload: %.2f%%\n", (float)offset/file_size *100);
    //发送文件
    signal(2, func);
    sendfile(socket_fd, fd, &offset, file_size - offset);

    printf("Upload: %.2f%%\n", (float)offset/file_size *100);

    if(trans_exit == 1){
        //有退出信号
        printf("Upload stopped.\n");
        signal(2, SIG_DFL);
        close(fd);
        close(socket_fd);
        exit(1);
    }

    int file_complete = 0;
    if(offset == file_size){
        recv(socket_fd, &file_complete, sizeof(int), MSG_WAITALL);
        if(file_complete == 1){
            printf("Upload success.\n");
        }
        else{
            printf("Upload failed.There is an error occurred during file transfer.\n");
        }
    }

    signal(2, SIG_DFL);
    close(fd);
    return 0;
}
